#ifndef CONVERSE_CONVERSEMANAGER_H
#define CONVERSE_CONVERSEMANAGER_H


#include <QObject>
#include <QVariant>
#include <QMap>
#include <QPointer>
#include <QMutex>


namespace Contact {
class AbstractContact;
class PrivateContact;
class GroupContact;
}

namespace Account {
class Member;
}

namespace Converse {

class AbstractConversation;
class PrivateConversation;
class GroupConversation;
class AbstractMessage;
class UnreadMessageEvent;
class MessageGroup;

class Manager : public QObject
{
    Q_OBJECT
public:
    typedef QList<AbstractConversation *> ConversationList;
    typedef QMap<qint64, AbstractConversation *> Finder;

private:
    explicit Manager(QObject *parent = 0);

private:
    static Manager *m_instance;

private:
    mutable QMutex m_mutex;
    ConversationList m_conversationList;

    Finder m_privateConversationFinder;
    Finder m_privateConversationByContactFinder;
    Finder m_groupConversationFinder;
    Finder m_groupConversationByContactFinder;

Q_SIGNALS:
    void messageReadFromLocal(AbstractMessage *message);
    void messageSend(AbstractMessage *message);
    void messageSent(AbstractMessage *message);
    void messageReceived(AbstractMessage *message);
    void dataInserted(int index, Converse::MessageGroup *messageGroup);
    void dataCleared();

private:
    void init();
    void setConnection() const;

private:
    void clearConversationFinder();
    void clearPrivateConversationFinder();
    void clearGroupConversationFinder();

    void deleteConversationList();

private:
    PrivateConversation *createPrivateConversation(qint64 id, Contact::PrivateContact *contact);
    GroupConversation *createGroupConversation(qint64 id, Contact::GroupContact *contact);

public:
    static Manager *instance(QObject *parent = 0);

public:
    inline const ConversationList &conversationList() const {
        return m_conversationList;
    }

public:
    bool changePrivateConversationId(AbstractConversation *conversation, qint64 id);

public:
    void clearData();

public slots:
    void onMessageReadFromLocal(AbstractMessage *message);
    void onMessageReceived(AbstractMessage *message);
    void onMessageSent(AbstractMessage *message);
    void onMessageSend(AbstractMessage *message);
    void onDataInserted(int index, Converse::MessageGroup *messageGroup);

public:
    AbstractConversation *findPrivateConversationById(qint64 id);
    AbstractConversation *findBySending(qint64 id);

    PrivateConversation *findPrivateConversationByPartnerId(qint64 id);
    GroupConversation *findGroupConversationByPartnerId(qint64 id);
    GroupConversation *findGroupConversationById(qint64 id);

public:
    PrivateConversation *appendPrivateConversation(qint64 id, Contact::PrivateContact *contact);
    GroupConversation *appendGroupConversation(qint64 id, Contact::GroupContact *contact);

public:
    int count() const;
    int size() const;

    bool containsPrivateConversation(qint64 id);
    bool containsGroupConversation(qint64 id);
    bool contains(AbstractConversation *conversation);
};

} // namespace Converse

#endif // CONVERSE_CONVERSEMANAGER_H
